﻿using System.Collections.Generic;

namespace DimensionsHelper.Common.Utils;

public static class CollectionHelper
{
    /// <summary>
    ///     二分查找函数
    ///     <see
    ///         cref="CollectionHelper.BinarySearch{TSource,TSearch}(IReadOnlyList{TSource},int,int,TSearch,BinarySearchComparer{TSource,TSearch})" />
    ///     使用的值比较回调，
    ///     <list type="number">
    ///         <item>如果x小于y，返回负数</item>
    ///         <item>如果x等于y, 返回0</item>
    ///         <item>如果x大于y，返回正数。</item>
    ///     </list>
    /// </summary>
    public delegate int BinarySearchComparer<in T1, in T2>(T1 x, T2 y);


    /// <summary>
    ///     简单的二分查找函数，在<paramref name="list" />列表中查找指定值。
    /// </summary>
    /// <typeparam name="TSource">列表元素类型</typeparam>
    /// <typeparam name="TSearch">查找值类型</typeparam>
    /// <param name="list">原始列表</param>
    /// <param name="start">起始索引</param>
    /// <param name="length">查找的长度</param>
    /// <param name="value">查找值</param>
    /// <param name="comparer">用于比较列表元素和查找值的回调函数</param>
    /// <returns>查找到的索引，如果未找到符合的，返回第一个超过查找值索引的补码.</returns>
    public static int BinarySearch<TSource, TSearch>(IReadOnlyList<TSource> list, int start, int length,
        TSearch value, BinarySearchComparer<TSource, TSearch> comparer)
    {
        int low = start;
        int high = length - 1;

        while (low <= high)
        {
            int mid = low + ((high - low) >> 1);
            int comp = comparer(list[mid], value);
            switch (comp)
            {
                case < 0:
                    low = mid + 1;
                    break;
                case > 0:
                    high = mid - 1;
                    break;
                default:
                    return mid;
            }
        }

        return ~low;
    }


    /// <summary>
    ///     <inheritdoc
    ///         cref="BinarySearch{TSource, TSearch}(IReadOnlyList{TSource}, int, int, TSearch, BinarySearchComparer{TSource, TSearch})" />
    /// </summary>
    public static int BinarySearch<TSource, TSearch>(IReadOnlyList<TSource> list, TSearch value,
        BinarySearchComparer<TSource, TSearch> comparer)
    {
        return BinarySearch(list, 0, list.Count, value, comparer);
    }


    public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> values)
    {
        foreach (T item in values)
        {
            collection.Add(item);
        }
    }

}